package org.mclll.xwangplugin.town.shop.listener;

import com.google.common.collect.Maps;
import de.tr7zw.nbtapi.NBT;
import de.tr7zw.nbtapi.iface.ReadableNBT;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import org.apache.commons.lang.StringUtils;
import org.black_ixx.bossshop.BossShop;
import org.black_ixx.bossshop.core.BSBuy;
import org.black_ixx.bossshop.core.BSShop;
import org.black_ixx.bossshop.core.prices.BSPriceType;
import org.black_ixx.bossshop.core.rewards.BSRewardType;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.jetbrains.annotations.Nullable;
import org.mclll.xwangplugin.log.GlobalLog;
import org.mclll.xwangplugin.log.LogUtil;
import org.mclll.xwangplugin.log.LoggerFactory;
import org.mclll.xwangplugin.town.command.executor.TownShopExecutor;
import org.mclll.xwangplugin.town.database.domain.TownDO;
import org.mclll.xwangplugin.town.database.domain.TownShopDO;
import org.mclll.xwangplugin.town.database.mapper.manage.TownManage;
import org.mclll.xwangplugin.town.database.mapper.manage.TownShopManage;
import org.mclll.xwangplugin.util.PlayerTools;

import java.util.Collections;
import java.util.Map;

import static org.mclll.xwangplugin.town.config.TownContext.*;

public class ShopListener implements Listener {

    public static final int COIN_GET_PER_SLOT = 12;
    public static final int COIN_GET_COUNT_SLOT = 13;
    public static final int HEART_STONE_GET_SLOT = 14;
    public static Map<Player, TownShopDO> PLAYER_SHOPPING = Maps.newHashMap();
    public static Map<String, Long> DELETE_SHOP_ITEM = Maps.newHashMap();
    private static Economy econ = null;
    private LogUtil log;

    public ShopListener() {
        log = LoggerFactory.get(GlobalLog.class);
    }

    @EventHandler
    public void bsShopListener(InventoryClickEvent event) {
        BossShop bs = (BossShop) Bukkit.getPluginManager().getPlugin("BossShopPro");
        Inventory clickedInventory = event.getClickedInventory();
        ItemStack clicked = event.getCurrentItem();
        if (bs == null || clickedInventory == null || !bs.getAPI().isValidShop(clickedInventory) || clicked == null || clicked.getType() == Material.AIR) {
            return;
        }
        ReadableNBT townShop = NBT.readNbt(clicked);
        Player player = (Player) event.getWhoClicked();
        // 返回操作不限制点击类型,
        Boolean back = townShop.getBoolean("BackTownShop");
        if (back) {
            clickedInventory.close();
            Bukkit.getServer().dispatchCommand(
                    Bukkit.getConsoleSender(),
                    "poitown shop " + PLAYER_SHOPPING.get(player).getTownUuid() + " " + player.getName()
            );
            return;
        }
        // 购买或确认购买
        boolean getOrConfirmGet = event.getClick() == ClickType.SHIFT_LEFT;
        // op删除商品
        boolean opDeleteItem = player.isOp() && event.getClick() == ClickType.DROP;
        // 操作类型错误返回
        if (!getOrConfirmGet && !opDeleteItem) {
            return;
        }
        String townShopUuid = townShop.getString("TownShopUuid");

        if (StringUtils.isNotBlank(townShopUuid)) {
            // op操作删除商品
            if (opDeleteItem) {
                Long lastOperationTime = DELETE_SHOP_ITEM.get(townShopUuid);
                if (lastOperationTime == null || System.currentTimeMillis() - lastOperationTime > 5000) {
                    DELETE_SHOP_ITEM.put(townShopUuid, System.currentTimeMillis());
                    player.sendMessage("再次操作确认删除");
                } else {
                    TownShopDO delParam = new TownShopDO();
                    delParam.setUuid(townShopUuid);
                    delParam.setIsDelete(true);
                    TownShopManage.updateByUuid(delParam);
                    clickedInventory.close();
                    player.sendMessage("成功删除商品");
                }
                return;
            }
            // ↑
            TownShopDO ts = TownShopManage.selectByUuid(townShopUuid);
            PLAYER_SHOPPING.put(player, ts);
            townShopGetConfirm(event, ts, bs, clickedInventory);
        }
        Boolean townShopGet = townShop.getBoolean("TownShopGet");
        if (townShopGet) {
            TownShopDO ts = PLAYER_SHOPPING.get(player);
            ItemStack reward = NBT.itemStackFromNBT(NBT.parseNBT(ts.getRewardJson()));
            if (reward == null) {
                log.info("商店数据错误，" + ts.getTownUuid());
                log.info("商店数据错误，" + ts.getTownUuid());
                log.info("商店数据错误，" + ts.getTownUuid());
                return;
            }
            if (!setupEconomy()) {
                log.info(" - Disabled due to no Vault dependency found!");
                return;
            }
            switch (event.getSlot()) {
                case COIN_GET_PER_SLOT:
                    if (!enoughSpaceGet(1, 1, player.getInventory())) {
                        player.sendMessage(BACKPACK_IS_FULL);
                        break;
                    }
                    if (costCoin(player, ts.getCoinGetPerPrice(), ts.getTownUuid())) {
                        player.getInventory().addItem(reward.asOne());
                        player.sendMessage(Component.text("成功购买的商品").color(NamedTextColor.GREEN)
                                .append(reward.displayName())
                                .append(Component.text(" x" + 1)));
                    }
                    break;
                case COIN_GET_COUNT_SLOT:
                    if (!enoughSpaceGet(reward.getMaxStackSize(), ts.getCoinGetCount(), player.getInventory())) {
                        player.sendMessage(BACKPACK_IS_FULL);
                        break;
                    }
                    if (costCoin(player, ts.getCoinGetCount() * ts.getCoinGetPerPrice(), ts.getTownUuid())) {
                        ItemStack coinGet = reward.clone();
                        coinGet.setAmount(ts.getCoinGetCount());
                        player.getInventory().addItem(coinGet);
                        player.sendMessage(Component.text("成功购买的商品").color(NamedTextColor.GREEN)
                                .append(reward.displayName())
                                .append(Component.text(" x" + ts.getCoinGetCount())));
                    }
                    break;
                case HEART_STONE_GET_SLOT:
                    if (!enoughSpaceGet(reward.getMaxStackSize(), ts.getPerHeartStoneGetCount(), player.getInventory())) {
                        player.sendMessage(BACKPACK_IS_FULL);
                    }
                    if (costHeartStone(player, ts.getTownUuid(), ts.getPerHeartStoneGetPrice())) {
                        ItemStack htGet = reward.clone();
                        htGet.setAmount(ts.getPerHeartStoneGetCount());
                        player.getInventory().addItem(htGet);
                        player.sendMessage(Component.text("成功购买的商品").color(NamedTextColor.GREEN)
                                .append(reward.displayName())
                                .append(Component.text(" x" + ts.getPerHeartStoneGetCount())));
                    }
                    break;
                default:
            }
        }
    }

    private boolean costHeartStone(Player player, String townUuid, int costCount) {
        int taxCount = costCount;
        @Nullable ItemStack[] contents = player.getInventory().getContents();
        for (int i = 0; i < contents.length; i++) {
            ItemStack item = contents[i];
            if (item == null || item.getType() == Material.AIR) {
                continue;
            }
            String mythicType = NBT.get(item, nbt -> {
                return nbt.getString("MYTHIC_TYPE");
            });
            if (!"心之石".equals(mythicType)) {
                continue;
            }
            if (item.getAmount() >= taxCount) {
                if (item.getAmount() == taxCount) {
                    contents[i] = null;
                } else {
                    item.setAmount(item.getAmount() - taxCount);
                }
                player.getInventory().setContents(contents);
                // 返还给城镇
                TownDO town = TownManage.selectByUuid(townUuid);
                TownDO updateParam = new TownDO();
                updateParam.setUuid(town.getUuid());
                updateParam.setSaveHartStone(town.getSaveHartStone() + (costCount / 2.0));
                TownManage.updateByUuid(updateParam);
                return true;
            } else {
                taxCount -= item.getAmount();
                contents[i] = null;
            }
        }
        player.sendMessage(NO_HAVE_HEART_STONE);
        return false;
    }

    private boolean costCoin(Player player, Double cost, String townUuid) {
        double balance = econ.getBalance(player);
        if (balance < cost) {
            player.sendMessage(MONEY_NOT_ENOUGH);
            return false;
        }
        EconomyResponse res = econ.withdrawPlayer(player, cost);
        // 返还一半给镇长
        TownDO town = TownManage.selectByUuid(townUuid);
        OfflinePlayer leader = PlayerTools.getOfflineOrOnlinePlayerByUuid(town.getLeaderUuid());
        econ.depositPlayer(leader, cost / 2);
        if (leader.isOnline()) {
            ((Player)leader).sendMessage(String.format(TOWN_SHOP_CALL_BACK, cost / 2));
        }
        player.sendMessage(String.format("金钱余额：%.2f", res.balance));
        return true;
    }


    private void townShopGetConfirm(InventoryClickEvent event, TownShopDO tsDO, BossShop bs, Inventory clickedInventory) {
        Player player = (Player) event.getWhoClicked();
        BSShop shop = bs.getAPI().getShop(TownShopExecutor.menuName);
        shop.getItems().clear();

        BSBuy showReward = bs.getAPI().createBSBuy(BSRewardType.Nothing, BSPriceType.Nothing,
                null, null, null, 10, null);
        ItemStack reward = NBT.itemStackFromNBT(NBT.parseNBT(tsDO.getRewardJson()));
        shop.addShopItem(showReward, reward, bs.getClassManager());
        if (tsDO.getCoinGetPerPrice() > 0) {
            addShopItem(bs, tsDO.getCoinGetPerPrice(), 1, "金钱", shop, Material.PAPER, 75028, COIN_GET_PER_SLOT);
            addShopItem(bs, tsDO.getCoinGetCount() * tsDO.getCoinGetPerPrice(), tsDO.getCoinGetCount(), "金钱", shop, Material.PAPER, 75028, COIN_GET_COUNT_SLOT);
        }
        if (tsDO.getPerHeartStoneGetCount() > 0) {
            addShopItem(bs, 1.0 * tsDO.getPerHeartStoneGetPrice(), tsDO.getPerHeartStoneGetCount(), "心之石", shop, Material.GOLD_NUGGET, 75025, HEART_STONE_GET_SLOT);
        }
        addShopReturn(bs, shop);
        clickedInventory.close();
        bs.getAPI().openShop(player, shop);
    }

    private void addShopReturn(BossShop bs, BSShop shop) {
        BSBuy backTo = bs.getAPI().createBSBuy(BSRewardType.Nothing, BSPriceType.Nothing,
                null, null, null, 26, null);
        ItemStack itemStack = new ItemStack(Material.ARROW);
        ItemMeta itemMeta = itemStack.getItemMeta();
        itemMeta.displayName(Component.text("&a◆ 返回 -"));
        itemMeta.lore(Collections.singletonList(Component.text("&7点击返回商店")));
        itemStack.setItemMeta(itemMeta);
        NBT.modify(itemStack, nbt -> {
            nbt.setBoolean("BackTownShop", true);
        });
        shop.addShopItem(backTo, itemStack, bs.getClassManager());
    }

    private static void addShopItem(BossShop bs, Double price, Integer count, String type, BSShop shop,
                                    Material iconType, Integer customModelData, int location) {
        BSBuy coinGetPerBs = bs.getAPI().createBSBuy(BSRewardType.Nothing, BSPriceType.Nothing,
                null, null, null, location, null);
        ItemStack icon = new ItemStack(iconType);
        ItemMeta iconMeta = icon.getItemMeta();
        iconMeta.displayName(Component.text("§2◆ Shift + 左键点击购买"));
        iconMeta.setCustomModelData(customModelData);
        iconMeta.lore(
                Collections.singletonList(
                        Component.text(String.format(TownShopExecutor.LINE_N_FORMAT, price, type, count))
                )
        );
        icon.setItemMeta(iconMeta);
        NBT.modify(icon, nbt -> {
            nbt.setBoolean("TownShopGet", true);
        });
        shop.addShopItem(coinGetPerBs, icon, bs.getClassManager());
    }

    private boolean enoughSpaceGet(int maxStack, int total, PlayerInventory playerInventory) {
        int count = 0;
        for (ItemStack content : playerInventory.getContents()) {
            if (content != null && content.getType() != Material.AIR) {
                ++count;
            }
        }
        // 减去，头盔，胸甲，裤头，靴子，副手
        ItemStack itemInOffHand = playerInventory.getItemInOffHand();
        if (itemInOffHand.getType() != Material.AIR) {
            --count;
        }
        for (ItemStack armorContent : playerInventory.getArmorContents()) {
            if (armorContent != null && armorContent.getType() != Material.AIR) {
                --count;
            }
        }
        // 减去，头盔，胸甲，裤头，靴子，副手
        return count + (total / maxStack + (total % maxStack == 0 ? 0 : 1)) <= playerInventory.getSize() - 5;
    }

    private boolean setupEconomy() {
        if (Bukkit.getServer().getPluginManager().getPlugin("Vault") == null) {
            return false;
        }
        RegisteredServiceProvider<Economy> rsp = Bukkit.getServer().getServicesManager().getRegistration(Economy.class);
        if (rsp == null) {
            return false;
        }
        econ = rsp.getProvider();
        return econ != null;
    }

}
